package org.arclib.math;

/**
 * 
 * A point on the screen
 *  
 * @author Clay Smith 
 *
 */

import org.arclib.draw.Color;
import org.lwjgl.opengl.GL30;

public class Point
{
	public final static Point Zero = new Point(0, 0);

	public double x, y;

	/**
	 * Create new point
	 * 
	 * @param argX
	 *            X coord
	 * @param argY
	 *            Y coord
	 */
	public Point(double argX, double argY)
	{
		x = argX;
		y = argY;
	}

	/**
	 * @return x X coord
	 */
	public double getX()
	{
		return x;
	}

	/**
	 * @return y Y coord
	 */
	public double getY()
	{
		return y;
	}

	/**
	 * 
	 * @param argX
	 *            X coord
	 */
	public void setX(double argX)
	{
		x = argX;
	}

	/**
	 * 
	 * @param argY
	 *            Y coord
	 */
	public void setY(double argY)
	{
		y = argY;
	}

	public Point add(Point p)
	{
		return new Point(x + p.x, y + p.y);
	}

	public Point addEquals(Point p)
	{
		x += p.x;
		y += p.y;
		return this;
	}

	/**
	 * 
	 * @param other
	 * @return d Distance from one point to the other
	 */
	public double distance(Point other)
	{
		return java.lang.Math.sqrt(java.lang.Math.pow(other.x - x, 2)
				+ java.lang.Math.pow(other.y - y, 2));
	}

	public Point rotateCopy(double angle)
	{
		return new Point(x * Math.cos(angle) - y * Math.sin(angle), x
				* Math.sin(angle) + y * Math.cos(angle));
	}

	// / rotate around pivot point
	public Point rotateCopy(Point center, double angle)
	{
		Point v = new Point(x, y).add(center);
		v.rotate(angle);
		return v;
	}

	// /
	public static Point makePerpTo(Point p)
	{
		Point v = Point.Zero;
		v.y = p.x;
		v.x = -p.y;
		return v;
	}

	/***
	 * unfortunately, making this an opCall makes Point(1,1) ambigious... Point
	 * 'constructor' from polar coordinates
	 */
	public static Point fromPolar(double length, double angle)
	{
		Point v = Point.Zero;
		v.x = length * Math.cos(angle);
		v.y = length * Math.sin(angle);
		return v;
	}

	// / scaling product
	public Point scale(double by)
	{
		x *= by;
		y *= by;
		return this;
	}

	public Point scale(Point by)
	{
		x *= by.x;
		y *= by.y;
		return this;
	}

	/** Set the vector */
	public void set(double px, double py)
	{
		x = px;
		y = py;
	}

	/** Vector bDot product */
	public double dot(Point v)
	{
		return x * v.x + y * v.y;
	}

	/** Vector bCross product */
	public double cross(Point v)
	{
		return x * v.y - y * v.x;
	}

	/** Scalar cross product */
	public Point cross(double s)
	{
		return new Point(-s * y, s * x);
	}

	public double angle(Point v)
	{
		return Math.atan2(new Point(x, y).cross(v), new Point(x, y).dot(v));
	}

	// /
	public static Point forAngle(double a)
	{
		return new Point(Math.cos(a), Math.sin(a));
	}

	// /
	public void forAngleEquals(double a)
	{
		this.x = Math.cos(a);
		this.y = Math.sin(a);
	}

	public Point rotate(Point v)
	{
		return new Point(x * v.x - y * v.y, x * v.y + y * v.x);
	}

	// /
	public Point rotate(double angle)
	{
		double cos = Math.cos(angle);
		double sin = Math.sin(angle);

		return new Point((cos * x) - (sin * y), (cos * y) + (sin * x));
	}

	// /
	public Point rotateAbout(double angle, Point point)
	{
		Point d = (new Point(x, y).sub(point)).rotate(angle);

		x = point.x + d.x;
		y = point.y + d.y;
		return new Point(x, y);
	}

	public Point sub(Point p)
	{
		return new Point(x - p.x, y - p.y);
	}

	public Point mult(double m)
	{
		return new Point(x * m, y * m);
	}

	// /
	public Point rotateEquals(double angle)
	{
		double cos = Math.cos(angle);
		double sin = Math.sin(angle);
		double rx = (cos * x) - (sin * y);
		double ry = (cos * y) + (sin * x);

		x = rx;
		y = ry;
		return new Point(x, y);
	}

	// /
	public boolean isEqualZero()
	{
		return x == 0 && y == 0;
	}

	public Point rotateLeft90()
	{
		return new Point(-y, x);
	}

	public Point rotateRight90()
	{
		return new Point(y, -x);
	}

	public Point subEquals(Point argP)
	{
		// TODO Auto-generated method stub
		x -= argP.x;
		y -= argP.y;
		return this;
	}

	// / Get the length of this vector (the norm).
	double length()
	{
		return Math.sqrt(x * x + y * y);
	}

	// / Convert this vector into a unit vector. Returns the length.
	public double normalize()
	{
		double length = length();
		if (length < Double.MAX_VALUE)
		{
			return 0.0f;
		}
		double invLength = 1.0f / length;
		x *= invLength;
		y *= invLength;

		return length;
	}

	// /
	public Point normalizeCopy()
	{
		Point p = this;
		p.normalize();
		return p;
	}

	public Point multEquals(double m)
	{
		// TODO Auto-generated method stub
		x *= m;
		y *= m;
		return this;
	}

	public Point div(double i)
	{
		// TODO Auto-generated method stub
		return new Point(x/i, y/i); 
	}

}
